// $Id: testAliRawReader.C 62788 2013-06-04 12:41:23Z richterm $

/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        * 
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/** @file   testAliRawReader.C
    @author Matthias Richter
    @date   
    @brief  Test macro/program for the AliRawReaderMemory
 */

#ifndef __CINT__
#include "TFile.h"
#include "TDatime.h"
#include "TRandom.h"
#include "TArrayI.h"
#include "TArrayC.h"
#include "TSystem.h"
#include "AliRawDataHeader.h"
#include "AliRawReaderFile.h"
#include "AliRawReaderMemory.h"
#include "AliRawHLTManager.h"
#include "AliDAQ.h"
#include "AliHLTSystem.h"
#include <ostream>
#endif //__CINT__

#ifndef __CINT__
const int sizeofAliRawDataHeader=sizeof(AliRawDataHeader);
#else
// cint does not handle sizeof correctly
const int sizeofAliRawDataHeader=32;
#endif

/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
//
// configuration of the test program
//
const char* tmpdir="/tmp/testAliRawReaderMemory";
bool gbVerbose=false;

/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
int GetRandom(int min, int max);
int FillRandomDDL(TArrayC& target);
int WriteDDL(TArrayC& ddl, int ddlid);
int CheckRawReader(AliRawReader* pRawReader, TArrayC* ddls, int* ddlids, int nofDDLs);
int CheckRawReaderMemory(TArrayC* ddlArray, int* ddlidArray, int nofDDLs);
int CheckRawReaderHLT(AliRawReader* pParent, TArrayC* ddls, int* ddlids, int nofDDLs);
int CheckDDL_ReadNext(AliRawReader* pRawReader, TArrayC& ddl, int ddlid);
int CheckDDL_ReadNextData(AliRawReader* pRawReader, TArrayC& ddl, int ddlid);
int CheckDDL_ReadNextChar(AliRawReader* pRawReader, TArrayC& ddl, int ddlid);
int CheckDDL_ReadMixed(AliRawReader* pRawReader, TArrayC& ddl, int ddlid);

int testAliRawReaderFile()
{
  int iResult=0;

  // cleanup old raw folders
  TString command;
  command.Form("rm -r %s 2> /dev/null", tmpdir);
  gSystem->Exec(command);
  gSystem->mkdir(tmpdir);

  // variable number of DDLs
  int nofDDLs=0;
  do {
    nofDDLs=GetRandom(2,10);
  } while (nofDDLs<2);

  // allocate buffers
  TArrayC* ddlArray=new TArrayC[nofDDLs];
  int* ddlidArray=new int[nofDDLs];

  // create DDL ids and content
  int i=0;
  do {
    int detectorId=GetRandom(0,5);
    ddlidArray[i]=GetRandom(0,AliDAQ::NumberOfDdls(detectorId)-1)+AliDAQ::DdlIDOffset(detectorId);
    
    // check for duplicate id
    int j=0;
    for (; j<i; j++)
      if (ddlidArray[i]==ddlidArray[j]) break;
    
    if (j!=i) continue; // try once again

    FillRandomDDL(ddlArray[i]);
    if (gbVerbose) cout << "simulating data for ddl " << ddlidArray[i] << " size " << ddlArray[i].GetSize() << endl;
    WriteDDL(ddlArray[i], ddlidArray[i]);
  } while (++i<nofDDLs);

  if (gbVerbose) cout << "checking AliRawReaderFile ..." << endl;
  TString rawdir=tmpdir;
  if (!rawdir.EndsWith("/")) rawdir+="/";
  AliRawReader* pRawReader=AliRawReader::Create(rawdir);
  if (!pRawReader) {
    cerr << "can not create RawReaderFile" << endl;
    return -1;
  }

  if (!pRawReader->NextEvent()) {
    cerr << "error: getting event from RawReaderFile failed" << endl;
    return -1;
  }

  if ((iResult=CheckRawReader(pRawReader, ddlArray, ddlidArray, nofDDLs))<0) {
    return iResult;
  }

  /////////////////////////////////////////////////////////////////////////////////////////
  // check AliRawReaderMemory
  if ((iResult=CheckRawReaderMemory(ddlArray, ddlidArray, nofDDLs))<0) {
    return iResult;
  }

  /////////////////////////////////////////////////////////////////////////////////////////

  // Matthias 2009-01-24
  // disable check of RawReaderHLT for the moment due to problems with loeding libHLTrec
  // from AliRAWHLTManager
//   if ((iResult=CheckRawReaderHLT(pRawReader, ddlArray, ddlidArray, nofDDLs))<0) {
//     return iResult;
//   }

  delete pRawReader;

  gSystem->Exec(command);
  return 0;
}

Bool_t seedSet=kFALSE;

/**
 * Get a random number in the given range.
 */
int GetRandom(int min, int max)
{
  if (max-min<2) return min;
  static TRandom rand;
  if (!seedSet) {
    TDatime dt;
    rand.SetSeed(dt.Get());
    seedSet=kTRUE;
  }
  return rand.Integer(max-min);
}

/**
 * Fill the array with random DDL data.
 * The function leaves space for the CDH, sets the size member of the
 * CDH either to the buffer size or 0xffffffff by a random decision.
 */
int FillRandomDDL(TArrayC& target)
{
  int size=0;
  do size=GetRandom(100, 10000);
  while (size<100);

  target.Set(size);

  // decide randomly whether to set size of 0xffffffff
  if (GetRandom(0,40)%4) {
    *((Int_t*)target.GetArray())=size;
  } else {
    *((UInt_t*)target.GetArray())=0xffffffff;    
  }
  for (int i=sizeofAliRawDataHeader; i<size; i++) {
    Int_t data=GetRandom(0,255);
    target.AddAt((UChar_t)data, i);
  }
  return size;
}

/**
 * Write the simulated DDL data to file
 * Creates the filename from the DDL naming convention using the
 * AliDAQ conventions. The file is written to folder tmpdir/raw0
 * whereas tmpdir can be adjusted above. 
 */
int WriteDDL(TArrayC& ddl, int ddlid)
{
  Int_t dummy=0;
  TString filename;
  filename.Form("%s/raw0", tmpdir);
  gSystem->mkdir(filename);
  filename.Form("%s/%s_%d.ddl", filename.Data(), AliDAQ::DetectorNameFromDdlID(ddlid, dummy), ddlid);
  FILE* fp=fopen(filename.Data(), "w");
  if (!fp) return -1;

  fwrite(ddl.GetArray(), 1, ddl.GetSize(), fp);
  fclose(fp);

  return 0;
}

/**
 * Check the AliRawReaderMemory
 *
 * Check consists of 3 steps:
 * - check with one ddl per cycle: SetMemory/SetEquipmentID method
 * - check with multiple buffers: AddBuffer method
 * - check with one ddl as constructor parameter and AddBuffer for the
 *   subsequent ddls
 *
 * @return -1 if check failed
 */
int CheckRawReaderMemory(TArrayC* ddlArray, int* ddlidArray, int nofDDLs)
{
  int iResult=0;
  int i=0;
  /////////////////////////////////////////////////////////////////////////////////////////
  if (gbVerbose) cout << "checking AliRawReaderMemory ..." << endl;
  AliRawReaderMemory* pRawReaderMemory=new AliRawReaderMemory;
  for (i=0; i<nofDDLs; i++) {
    if (!pRawReaderMemory->SetMemory((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize())) {
      cerr << "AliRawReaderMemory::SetMemory failed for block " << i << endl;
      return -1;
    }
    pRawReaderMemory->SetEquipmentID(ddlidArray[i]);
    if (i==0 && !pRawReaderMemory->NextEvent()) {
      cerr << "error: getting event from RawReaderMemory failed" << endl;
      return -1;
    }

    if ((iResult=CheckRawReader(pRawReaderMemory, ddlArray+i, ddlidArray+i, 1))<0) {
      return iResult;
    }
  }
  if (pRawReaderMemory->NextEvent()) {
    cerr << "error: RawReaderMemory::NextEvent returns true, while no more events should be there" << endl;
    return -1;
  }

  /////////////////////////////////////////////////////////////////////////////////////////
  if (gbVerbose) cout << "checking AliRawReaderMemory with multiple buffers ..." << endl;
  pRawReaderMemory->RewindEvents();
  pRawReaderMemory->ClearBuffers();
  for (i=0; i<nofDDLs; i++) {
    if (!pRawReaderMemory->AddBuffer((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize(), ddlidArray[i])) {
      cerr << "AliRawReaderMemory::AddBuffer failed for block " << i << endl;
      return -1;
    }
  }
  if (!pRawReaderMemory->NextEvent()) {
    cerr << "error: getting event from RawReaderMemory failed" << endl;
    return -1;
  }

  if ((iResult=CheckRawReader(pRawReaderMemory, ddlArray, ddlidArray, nofDDLs))<0) {
    return iResult;
  }
  
  if (pRawReaderMemory->NextEvent()) {
    cerr << "error: RawReaderMemory::NextEvent returns true, while no more events should be there" << endl;
    return -1;
  }
  delete pRawReaderMemory;
  pRawReaderMemory=NULL;

  /////////////////////////////////////////////////////////////////////////////////////////
  if (gbVerbose) cout << "checking AliRawReaderMemory constructor ..." << endl;
  for (i=0; i<nofDDLs; i++) {
    if (!pRawReaderMemory) {
      pRawReaderMemory=new AliRawReaderMemory((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize());
      if (pRawReaderMemory) {
	pRawReaderMemory->SetEquipmentID(ddlidArray[i]);
      } else {
	cerr << "can not create AliRawReaderMemory with parameters" << endl;
	return -1;
      }
    }else if (!pRawReaderMemory->AddBuffer((UChar_t*)ddlArray[i].GetArray(), ddlArray[i].GetSize(), ddlidArray[i])) {
      cerr << "AliRawReaderMemory::AddBuffer failed for block " << i << endl;
      return -1;
    }
  }
  if (!pRawReaderMemory->NextEvent()) {
    cerr << "error: getting event from RawReaderMemory failed" << endl;
    return -1;
  }

  if ((iResult=CheckRawReader(pRawReaderMemory, ddlArray, ddlidArray, nofDDLs))<0) {
    return iResult;
  }
  
  if (pRawReaderMemory->NextEvent()) {
    cerr << "error: RawReaderMemory::NextEvent returns true, while no more events should be there" << endl;
    return -1;
  }

  delete pRawReaderMemory;
  pRawReaderMemory=NULL;

  return iResult;
}

/**
 * Check the AliRawReaderHLT
 *
 * Open the AliRawReaderHLT from the parent reader without any HLTOUT
 * options, i.e. all requests are just forwarded.
 *
 * @return -1 if check failed
 */
int CheckRawReaderHLT(AliRawReader* pParent, TArrayC* ddls, int* ddlids, int nofDDLs)
{
  if (gbVerbose) cout << "checking AliRawReaderHLT ..." << endl;

  int iResult=0;
  pParent->RewindEvents();
  pParent->Reset();
  TString arg;
//   Int_t dummy=0;
//   for (i=0; i<nofDDLs; i++) {
//     if (!arg.Contains(AliDAQ::DetectorNameFromDdlID(ddlidArray[i], dummy))) {
//       arg+=" "; arg+=AliDAQ::DetectorNameFromDdlID(ddlidArray[i], dummy);
//     }
//   }

  AliRawReader* pRawReaderHLT=AliRawHLTManager::CreateRawReaderHLT(pParent, arg.Data());
  if (!pRawReaderHLT) {
    cerr << "can not create HLT RawReader" << endl;
    return -1;
  }

  if (!pRawReaderHLT->NextEvent()) {
    cerr << "error: getting event from HLT RawReader failed" << endl;
    return -1;
  }

  if ((iResult=CheckRawReader(pRawReaderHLT, ddls, ddlids, nofDDLs))<0) {
    return iResult;
  }

  delete pRawReaderHLT;
  return iResult;
}

/**
 * Check a RawReader, compare with the corresponding simulated data.
 * The corresponding simulated data is searched from the array via the current
 * equipment id. The check consists of 4 steps:
 * - data comparison by ReadNext
 * - data comparison by ReadNextData
 * - data comparison by ReadNextChar
 * - data comparison by mixed reading: ReadNextInt/Short/Char/Data
 * 
 * @return -1 if failed
 */
int CheckRawReader(AliRawReader* pRawReader, TArrayC* ddls, int* ddlids, int nofDDLs)
{
  int iResult=0;
  int count=0;
  // 1st pass: check AliRawReader::ReadNext()
  while (pRawReader->ReadHeader()) {
    int id=pRawReader->GetEquipmentId();
    int i=0;
    for (i=0; i<nofDDLs; i++) {
      if (ddlids[i]==id) break;
    }
    if (i==nofDDLs) {
      cerr << "error: can not find ddl id " << id << endl;
      return -1;
    }

    if ((iResult=CheckDDL_ReadNext(pRawReader, ddls[i], ddlids[i]))<0) return iResult;
    count++;
  }
  if (count<nofDDLs) {
    cerr << "less than the available blocks found from RawReader" << endl;
    return -1;
  }
  
  // 2nd pass: check AliRawReader::ReadNextData()
  count=0;
  pRawReader->Reset();
  while (pRawReader->ReadHeader()) {
    int id=pRawReader->GetEquipmentId();
    int i=0;
    for (i=0; i<nofDDLs; i++) {
      if (ddlids[i]==id) break;
    }
    if (i==nofDDLs) {
      cerr << "error: can not find ddl id " << id << endl;
      return -1;
    }

    if ((iResult=CheckDDL_ReadNextData(pRawReader, ddls[i], ddlids[i]))<0) return iResult;
    count++;
  }
  if (count<nofDDLs) {
    cerr << "less than the available blocks found from RawReader" << endl;
    return -1;
  }

  // 3rd pass: check AliRawReader::ReadNextData()
  count=0;
  pRawReader->Reset();
  while (pRawReader->ReadHeader()) {
    int i=0;
    do {
      int id=pRawReader->GetEquipmentId();
      for (i=0; i<nofDDLs; i++) {
	if (ddlids[i]==id) break;
      }
      if (i==nofDDLs) {
	cerr << "error: can not find ddl id " << id << endl;
	return -1;
      }
      count++;

      if ((iResult=CheckDDL_ReadNextChar(pRawReader, ddls[i], ddlids[i]))<0) return iResult;
    }
    // note: the ReadHeader is hidden in the ReadNextChar
    while (iResult!=ddlids[i]);
  }
  if (count<nofDDLs) {
    cerr << "less than the available blocks found from RawReader" << endl;
    return -1;
  }

  // 4th pass: check mixed AliRawReader::ReadNext*()
  count=0;
  pRawReader->Reset();
  while (pRawReader->ReadHeader()) {
    int id=pRawReader->GetEquipmentId();
    int i=0;
    for (i=0; i<nofDDLs; i++) {
      if (ddlids[i]==id) break;
    }
    if (i==nofDDLs) {
      cerr << "error: can not find ddl id " << id << endl;
      return -1;
    }

    if ((iResult=CheckDDL_ReadMixed(pRawReader, ddls[i], ddlids[i]))<0) return iResult;
    count++;
  }
  if (count<nofDDLs) {
    cerr << "less than the available blocks found from RawReader" << endl;
    return -1;
  }

  return iResult;
}

/**
 * Check RawReaders ReadNext function and compare data with simulated data
 * of the provided buffer.
 */
int CheckDDL_ReadNext(AliRawReader* pRawReader, TArrayC& ddl, int ddlid)
{
  int dataSize=pRawReader->GetDataSize();
  if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) {
    cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl;
    return -1;
  }
  TArrayC buffer(dataSize);
  UChar_t* pTgt=(UChar_t*)buffer.GetArray();
  
  if (!pRawReader->ReadNext(pTgt, buffer.GetSize())) {
    cerr << "error: reading " << buffer.GetSize() << " byte(s) from ReadNext (ddl " << ddlid << ")" << endl;
    return -1;
  }

  if (ddlid!=pRawReader->GetEquipmentId()) {
    cerr << "error: ReadMixed ddl id missmatch after ReadNext: reqired id " << ddlid << " got " << pRawReader->GetEquipmentId() << endl;
    return -1;
  }

  TString sizeStr;
  if (*((UInt_t*)ddl.GetArray())==0xffffffff) {
    sizeStr=" (0xffffffff)";
  } else {
    sizeStr.Form(" (%d)", ddl.GetSize());
  }
  if (gbVerbose) cout << "verify ReadNext: ddl " << ddlid << sizeStr << endl;
  if (memcmp(ddl.GetArray()+sizeofAliRawDataHeader, buffer.GetArray(), buffer.GetSize())!=0) {
    cerr << "error: verification of ddl " << ddlid << ")" << endl;
    return -1;
  }
  return 0;
}

/**
 * Check RawReaders ReadNextData function and compare data with simulated data
 * of the provided buffer.
 */
int CheckDDL_ReadNextData(AliRawReader* pRawReader, TArrayC& ddl, int ddlid)
{
  int dataSize=pRawReader->GetDataSize();
  if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) {
    cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl;
    return -1;
  }

  UChar_t* pTgt=NULL;  
  if (!pRawReader->ReadNextData(pTgt) || pTgt==NULL) {
    cerr << "error: reading " << dataSize << " byte(s) from ReadNextData (ddl " << ddlid << ")" << endl;
    return -1;
  }

  if (gbVerbose) cout << "verify ReadNextData: ddl " << ddlid << endl;
  if (memcmp(ddl.GetArray()+sizeofAliRawDataHeader, pTgt, dataSize)!=0) {
    cerr << "error: verification of ddl " << ddlid << endl;
    return -1;
  }
  return 0;
}

/**
 * Check RawReaders ReadNextChar function and compare data with simulated data
 * of the provided buffer.
 */
int CheckDDL_ReadNextChar(AliRawReader* pRawReader, TArrayC& ddl, int ddlid)
{
  int iResult=ddlid;
  int dataSize=pRawReader->GetDataSize();
  if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) {
    cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl;
    return -1;
  }

  if (gbVerbose) cout << "verify ReadNextChar: ddl " << ddlid << endl;
  static int offset=0;
  int i=sizeofAliRawDataHeader+offset;
  UChar_t data=0;
  Bool_t haveData=kFALSE;
  for (; (haveData=pRawReader->ReadNextChar(data)) && i<ddl.GetSize(); i++) {
    if (data!=(UChar_t)ddl.At(i)) {
      cerr << "error: at position " << i << " of ddl " << ddlid << ": read " << (UShort_t)data << " required " << (UShort_t)(UChar_t)ddl.At(i) << endl;
      return -1;
    }
  }

  if (i<ddl.GetSize()) {
    cerr << "error: reading data of ddl " << ddlid << ": " << i << " of " << ddl.GetSize() << endl;
    return -1;
  }
  if (pRawReader->GetEquipmentId()>=0 && ddlid!=pRawReader->GetEquipmentId()) {
    //cerr << "error: ddl id missmatch, expecting " << ddlid << " got " << pRawReader->GetEquipmentId() << endl;
    // thats not an error condition, RawReader just changes silently to the next DDL
    iResult=pRawReader->GetEquipmentId();
    offset=1;
  } else {
    offset=0;
  }
  if (haveData && iResult==ddlid) {
    cerr << "error: size missmatch in ddl " << ddlid << ": still data available after " << ddl.GetSize() << " byte(s)"<< endl;
    return -1;
  }
  return iResult;
}

/**
 * Check RawReaders ReadNextInt/Short/Char/Data functions and compare data with
 * simulated data of the provided buffer.
 */
int CheckDDL_ReadMixed(AliRawReader* pRawReader, TArrayC& ddl, int ddlid)
{
  int dataSize=pRawReader->GetDataSize();
  if (ddl.GetSize()!=dataSize+sizeofAliRawDataHeader) {
    cerr << "error: size mismatch in ddl " << ddlid << ": " << dataSize+sizeofAliRawDataHeader << " required " << ddl.GetSize() << endl;
    return -1;
  }

  TArrayC readBytes(7);

  // we do not need to test if there is only one byte
  if (dataSize<=readBytes.GetSize()) return 0;

  UInt_t i=0;
  for (; i<(readBytes.GetSize()/sizeof(UInt_t))*sizeof(UInt_t); i+=sizeof(UInt_t)) {
    UInt_t data=0;
    if (!pRawReader->ReadNextInt(data)) {
      cerr << "error: reading 1 int from ReadNextInt position " << i << " (ddl " << ddlid << ")" << endl;
      return -1;
    }
#ifndef R__BYTESWAP
   data = (((data & 0x000000ffU) << 24) | ((data & 0x0000ff00U) <<  8) |
           ((data & 0x00ff0000U) >>  8) | ((data & 0xff000000U) >> 24));
#endif
   *(reinterpret_cast<UInt_t*>(readBytes.GetArray()+i))=data;
  }
  for (; i<(readBytes.GetSize()/sizeof(UShort_t))*sizeof(UShort_t); i+=sizeof(UShort_t)) {
    UShort_t data=0;
    if (!pRawReader->ReadNextShort(data)) {
      cerr << "error: reading 1 short from ReadNextShort position " << i << " (ddl " << ddlid << ")" << endl;
      return -1;
    }
#ifndef R__BYTESWAP
    data = (((data & 0x00ffU) <<  8) | ((data & 0xff00U) >>  8)) ;
#endif
    *(reinterpret_cast<UShort_t*>(readBytes.GetArray()+i))=data;
  }
  for (; i<(UInt_t)readBytes.GetSize(); i++) {
    if (!pRawReader->ReadNextChar(*(reinterpret_cast<UChar_t*>(readBytes.GetArray()+i)))) {
      cerr << "error: reading 1 byte from ReadNextChar position " << i << " (ddl " << ddlid << ")" << endl;
      return -1;
    }
  }
  UChar_t* pTgt=NULL;
  // TODO: here we have a problem with the HLT Raw Reader, due to the
  // behavior of ReadNextData. It returns the pointer to either
  // - the remaining data within this block. Thogh, GetDataSize still
  //   returns the full lenght
  // - if no more data available switch to next equipment
  // Currently, the RawReaderHLT switches immediately to the next
  // equipment, considered the GetDataSize behavior this is correct, but
  // different from the others
  // 
  // Use ReadNext for the moment in order to get the test scheme working.
  //if (!pRawReader->ReadNextData(pTgt) || pTgt==NULL) {
  TArrayC buffer(dataSize-readBytes.GetSize());
  pTgt=(UChar_t*)buffer.GetArray();
  if (!pRawReader->ReadNext(pTgt, buffer.GetSize())) {
    cerr << "error: reading " << dataSize << " byte(s) from ReadNextData (ddl " << ddlid << ")" << endl;
    return -1;
  }
  if (ddlid!=pRawReader->GetEquipmentId()) {
    cerr << "error: ReadMixed ddl id missmatch after ReadNextData: reqired id " << ddlid << " got " << pRawReader->GetEquipmentId() << endl;
    return -1;
  }

  if (gbVerbose) cout << "verify ReadNextInt/Short/Char/Data: ddl " << ddlid << endl;
  if (memcmp((ddl.GetArray())+sizeofAliRawDataHeader, readBytes.GetArray(), readBytes.GetSize())!=0) {
    cerr << "error: verification of mixed ReadNextInt/Short/Char failed in ddl " << ddlid << endl;
    return -1;
  }
  if (memcmp((ddl.GetArray())+readBytes.GetSize()+sizeofAliRawDataHeader, pTgt, dataSize-readBytes.GetSize())!=0) {
    cerr << "error: verification of mixed ReadNext ddl " << ddlid << endl;
    return -1;
  }
  return 0;
}

int main(int /*argc*/, const char** /*argv*/)
{
  int iResult=testAliRawReaderFile();
  if (iResult<0) {
    cerr << "check failed, repeat in verbose mode ..." << endl;
    gbVerbose=true;
    iResult=testAliRawReaderFile();
  }
  return iResult;
}
